﻿using Microsoft.Extensions.Caching.Redis;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CacheService.Standard
{
    public class RedisForCache : ICache
    {
        protected IDatabase _cache;

        private ConnectionMultiplexer _connection;
        private readonly string _instance;

        public RedisForCache(RedisCacheOptions options, int database = 0)
        {
            _connection = ConnectionMultiplexer.Connect(options.Configuration);
            _cache = _connection.GetDatabase(database);
            _instance = options.InstanceName;
        }
        /// <summary>
        /// 各个实例名区分不同的Key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private string overrideKey(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                throw new ArgumentNullException(nameof(key));
            }
            return _instance + key;
        }
        void ICache.delete(string key)
        {
            _cache.KeyDelete(overrideKey(key));
        }

        T ICache.get<T>(string key)
        {
            try
            {
                var value = _cache.StringGet(overrideKey(key));
                return JsonConvert.DeserializeObject<T>(value);
            }
            catch
            {
                return default(T);
            }
        }

        IDictionary<string, object> ICache.getMany(IEnumerable<string> keys)
        {
            var dict = new Dictionary<string, object>();
            keys.ToList().ForEach(item => dict.Add(overrideKey(item), JsonConvert.DeserializeObject(_cache.StringGet(overrideKey(item)))));
            return dict;
        }

        bool ICache.hasKey(string key)
        {
            return _cache.KeyExists(overrideKey(key));
        }

        void ICache.set(string key, object content, int time)
        {
            _cache.StringSet(overrideKey(key),JsonConvert.SerializeObject(content), TimeSpan.FromSeconds(time));
        }

        void ICache.setWithLasting(string key, object content)
        {
            _cache.StringSet(overrideKey(key), JsonConvert.SerializeObject(content));
        }

        void ICache.List(string key, int index,object content)
        {
            long i = 0;
            try
            {
                i = Convert.ToInt32(_cache.StringGet(overrideKey($"{key}_index_{index}")));
                if (i > 0)
                {
                    _cache.ListSetByIndex(overrideKey(key), i, JsonConvert.SerializeObject(content));
                }
            }
            catch
            {
                
            }
            if (i == 0)
            {
                i = _cache.ListLeftPush(overrideKey(key), JsonConvert.SerializeObject(content));
                _cache.StringSet(overrideKey($"{key}_index_{index}"), i);
            }
            
        }

        T ICache.getListItem<T>(string key, int index)
        {
            var i = Convert.ToInt32(_cache.StringGet(overrideKey($"{key}_index_{index}")));
            var item = _cache.ListGetByIndex(overrideKey(key), i);
            return JsonConvert.DeserializeObject<T>(item);
        }

        List<T> ICache.getList<T>(string key)
        {
            var items = _cache.ListRange(overrideKey(key));
            var list = new List<T>();
            foreach (var item in items)
            {
                list.Add(JsonConvert.DeserializeObject<T>(item));
            }
            return list;
        }
    }
}
